package md5Experiments;

import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;

public class Equation {
	private long value; /*
	0-511	-> variable
	512		-> true
	513		-> false
	514 	-> not
	515 	-> and
	516 	-> or
	517 	-> xor
	518 	-> nand
	519 	-> nor
	520 	-> xnor*/
	private Equation left;
	private Equation right;
	private long size;
	
	public static final int V_TRUE = 512;
	public static final int V_FALSE = 513;
	public static final int V_NOT = 514;
	public static final int V_AND = 515;
	public static final int V_OR = 516;
	public static final int V_XOR = 517;
	public static final int V_NAND = 518;
	public static final int V_NOR = 519; 
	public static final int V_XNOR = 520;
	
	Equation (){
		value = -1;
		left = null;
		right = null;
		size = 1;
	}
	
	Equation (long value){
		this.value = value;
		left = null;
		right = null;
		size = 1;
	}
	
	Equation (long value, Equation right){
		this.value = value;
		this.right = right;
		left = null;
		size = 1 + right.size;
		process();
	}
	
	Equation (long value, Equation left, Equation right){
		this.value = value;
		this.left = left;
		this.right = right;
		size = 1 + right.size + left.size;
		process();
	}
	
	public void process(){
		if (value == V_NOT){
			if (right.value == V_FALSE){
				right = null;
				value = V_TRUE;
			}
			else if (right.value == V_TRUE){
				right = null;
				value = V_FALSE;
			}
			else if (right.value == V_NOT){
				value = right.right.value;
				left = right.right.left;
				right = right.right.right;
			}
			else if (right.value > V_NOT && right.value <= V_XNOR){
				value = 515 + ((right.value + 4)%6);
				left = right.left;
				right = right.right;
			}
			
		} else if (value == V_XOR){
			if (right.value == V_FALSE){
				value = left.value;
				right = left.right;
				left = left.left;
			}
			else if (right.value == V_TRUE){
				right = left;
				left = null;
				value = V_NOT;
				process();
			}
			else if (left.value == V_FALSE){
				value = right.value;
				left = right.left;
				right = right.right;
			}
			else if (left.value == V_TRUE){
				left = null;
				value = V_NOT;
				process();
			}
		} else if (value == V_AND){
			if (right.value == V_FALSE){
				value = V_FALSE;
				right = null;
				left = null;
			}
			else if (right.value == V_TRUE){
				value = left.value;
				right = left.right;
				left = left.left;
			}
			else if (left.value == V_FALSE){
				value = V_FALSE;
				right = null;
				left = null;
			}
			else if (left.value == V_TRUE){
				value = right.value;
				left = right.left;
				right = right.right;
			}
		} else if (value == V_OR){
			if (right.value == V_FALSE){
				value = left.value;
				right = left.right;
				left = left.left;				
			}
			else if (right.value == V_TRUE){
				value = V_TRUE;
				right = null;
				left = null;				
			}
			else if (left.value == V_FALSE){
				value = right.value;
				left = right.left;
				right = right.right;				
			}
			else if (left.value == V_TRUE){
				value = V_TRUE;
				right = null;
				left = null;				
			}
		}
	}
	
	public void print() throws FileNotFoundException, UnsupportedEncodingException{
		
		if (left != null){
			System.out.print("( ");
			left.print();
		}
		else if (right != null)
			System.out.print("( ");
		
		if (value < 512)
			System.out.print("M" + value + " ");
		else if (value == 512)
			System.out.print("T ");
		else if (value == 513)
			System.out.print("F ");
		else if (value == 514)
			System.out.print("NOT ");
		else if (value == 515)
			System.out.print("AND ");
		else if (value == 516)
			System.out.print("OR ");
		else if (value == 517)
			System.out.print("XOR ");
		else if (value == 518)
			System.out.print("NAND ");
		else if (value == 519)
			System.out.print("NOR ");
		else if (value == 520)
			System.out.print("XOR ");
		else
			System.out.print("? ");
		
		if (right != null){
			right.print();
			System.out.print(") ");
		
		}
	}
	
	public long getDepth() {
		return size;
		/*int d = 1;
		if (left != null)
			d += left.getDepth();
		System.out.println(d);
		return d;*/
	}

	public long getValue() {
		return value;
	}

	public void setValue(long value) {
		this.value = value;
	}

	public Equation getLeft() {
		return left;
	}

	public void setLeft(Equation left) {
		this.left = left;
	}

	public Equation getRight() {
		return right;
	}

	public void setRight(Equation right) {
		this.right = right;
	}
}
